﻿using Qing.Lang;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Proto {

    public class CreateTimer : Native {
        public override string Name { get; set; } = "创建定时器";
        public override string Desc { get; set; } = "参数1-整数1，参数2-代码块|函数，可选参数3-逻辑；创建定时器，参数1为间隔毫秒数，参数2为定时执行的代码块或函数，可选参数3设置定时器是否忽略异常，默认为真";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
            if (args.Count < 2) {
                return Expr.Err("创建定时器的参数不足");
            }
            if (args[0].Tp != TP.Int || (args[1].Tp != TP.Brace && args[1].Tp != TP.Func)) {
                return Expr.Err("创建定时器的参数类型错误");
            }

            bool ignoreErr = true;
            if(args.Count > 2) {
                ignoreErr = args[2].ToBool();
            }

            return new Expr(TP.Obj, new TimerObj(args[0].Int(), args[1], ignoreErr));
        }

    }


    public class TimerObj : Obj {

        public Expr Body { get; set; } = Expr.NoneExpr;

        public int Span { get; set; } = 1000;

        public bool IgnoreErr { get; set; } = true;

        public List<Expr> defaultTimeUpArgs = new List<Expr>();

        public TimerObj(int span, Expr body, bool ignoreErr=true) {
            System.Timers.Timer T = new System.Timers.Timer(span);
            T.AutoReset = true;
            T.Elapsed += new System.Timers.ElapsedEventHandler(TimerUp);
            Raw = T;
            Span = span;
            Body = body;
            IgnoreErr = ignoreErr;
            
            Env.Timers.Add(T);

            Map["@启动"] = new Expr(new TimerStart());
            Map["@停止"] = new Expr(new TimerStop());

            Map["#间隔"] = new Expr(TP.Prop, new BindSpan(this));
            Map["#忽略异常"] = new Expr(TP.Prop, new BindIgnoreErr(this));
        }


        private void TimerUp(object sender, System.Timers.ElapsedEventArgs e) {
            System.Timers.Timer T = (System.Timers.Timer)Raw;
            Ctx? ctx = null;
            Expr ans = Expr.NoneExpr;
            if (Body.Tp == TP.Brace) {
                ctx = Body.Ctx();
                ans = Expr.EvalExprs(Body.List!, ctx);
            } else if (Body.Tp == TP.Func) {
                Func f = Body.Func();
                ctx = f.BindCtx;
                ans = f.Run(defaultTimeUpArgs, ctx);
            }

            if (ans.Tp == TP.Err) {
                Env.LibCtx!.GetNow("@显示").Native().Run(new List<Expr> { ans }, ctx!);
                if (!IgnoreErr) {
                    T.Stop();
                }
            }
        }


        class TimerStart : Native {
            public override string Name { get; set; } = "启动";
            public override string Desc { get; set; } = "可选参数1-逻辑，返回逻辑；启动定时器，可选参数1设置是否忽略异常，默认为真";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
                if(args.Count > 0) {
                    TimerObj timer = (TimerObj)obj!;
                    timer.IgnoreErr = args[0].ToBool();
                }

                System.Timers.Timer T = (System.Timers.Timer)obj!.Raw;
                T.Start();
                return new Expr(TP.Bool, true);
            }

        }

        class TimerStop : Native {
            public override string Name { get; set; } = "停止";
            public override string Desc { get; set; } = "无参，返回逻辑；停止定时器";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
                System.Timers.Timer T = (System.Timers.Timer)obj!.Raw;
                T.Stop();
                Env.Timers.Remove(T);
                return new Expr(TP.Bool, true);
            }

        }


        class BindSpan : Prop {
            public BindSpan(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx = null) {
                return new Expr(TP.Int, ((TimerObj)obj).Span);
            }
            public override Expr Qset(Expr val, Ctx? ctx = null) {
                return Expr.Err("无法修改定时器间隔时间");
            }
        }

        class BindIgnoreErr : Prop {
            public BindIgnoreErr(Obj obj) : base(obj) { }

            public override Expr Qget(Ctx? ctx = null) {
                return new Expr(TP.Bool, ((TimerObj)obj).IgnoreErr);
            }
            public override Expr Qset(Expr val, Ctx? ctx = null) {
                ((TimerObj)obj).IgnoreErr = val.ToBool();
                return val;
            }
        }



    }
}
